Part 14: Equity First Bank
Part 14 - Equity First Bank=== Trash World Inbox ===
GuavaMoment posted:
My 216 solution is not elegant. Mostly identical to yours, but I run 21 lines of "Copy 75 F", until X < 2500, where I run 9 lines of "Copy 75 F" until X < 750, then keep alternating between copying 75 and testing every time until X is zero.
silentsnack posted:
Looking at my solutions... I don't even remember writing this but aside from obviously being the product of trial and error it seems crude/unfinished? Maybe I'm just tired but I'm not seeing what it does all that differently, other than minor improvements like combining COPY F X and an ADDI X F X operation into ADDI F F X.
But somehow the stats are showing 195/75/3code:
;XA GRAB 300 COPY F X WIPE LINK 800 GRAB 199 MARK FIND TEST F = X SEEK 2 FJMP FIND SEEK -1 COPY F M ;XB LINK 800 LINK 799 GRAB M SEEK 2 ADDI F F X @REP 7 ADDI X F X @END MARK ADD ADDI X F X TEST EOF FJMP ADD SEEK -999 SEEK 2 DIVI X 1800 T MODI X 1800 X MARK WRITE24 @REP 24 COPY 75 F @END SUBI T 1 T TJMP WRITE24 DIVI X 225 T FJMP END MODI X 225 X MARK WRITE3 SUBI T 1 T @REP 3 COPY 75 F @END TJMP WRITE3 MARK END TEST X > 75 FJMP BREAK SUBI X 75 X COPY 75 F JUMP END MARK BREAK COPY X F
=== Equity First Bank ===
Just when I think I'm decent at pretending to be human, I find there's another parameter to add.
Two votes for "I thought an AI would be way faster", and five for the winning option.
How long have you pretended to be human?
Oh, pretty much from the start.
It's kind of a thing that I do.
Remember when I surprised you? That was a good one.
Let's continue.
Yeah, let's.
That sounds... chaotic.
How much does money affect behavior?
A lot, right?
Two votes for "Some behaviors aren't affected", five for the other choice.
Yeah, a lot.
I'm going to do an experiment involving wealth redistribution.
Sudden, random wealth redistribution.
This should be fun.
OST: Leave No Trace
The assignment:
- Dispense all available cash from all connected ATMs.
- For more information see "Network Exploration: Equity First Bank" in the first issue of the zine.
The max code size for this assignment is 50 lines.
Okay, so we don't really need to mess with the account files. Let's take a quick peek though.
It's basically as the zine says. Files have an account number and name and then a bunch of transactions. There's also a file 199 but that seems to just contain a list of the other file names. Nothing very exciting.
Messing around with the ATMs a bit I quickly learned two things: the #DISP register only accepts exactly 20 as input. You can't tell it to dispense $40 to make it spit out two bills at once. And if you tell it to dispense bills when the #CASH register is empty, the entire host will error out, which immediately fails the "Leave no trace" goal.
Also, the attached ATM hosts actually differ for each test case. The LINK ids are always between 800 and 806 inclusive but it's often not the complete set.
So, the first challenge is getting EXAs to all the ATMs. This code will work:
I can think of quite a few ways to do this, some a bit faster than others. For instance I could just make 7 EXAs and hardcode the different LINK instructions to 800 - 806. But since the IDs are sequential, using a REPL clone loop seems a bit more straightforward and probably makes the program smaller.
The problem is that I need to have a way to stop the loop, otherwise it keeps spawning new clones forever, and we can't leave any EXAs running around.
I decided to handle that with a cleanup EXA that just kills the cloning EXA after its timer runs out.
Next, dispensing cash from all the ATMs. Just to have something working I started with this naive solution:
code:
LINK 800
LINK 800
LINK 800
REPL CLEANUP
COPY 799 X
MARK CLONE
ADDI 1 X X
REPL CLONE
LINK X
COPY #CASH T
MARK DISPLOOP
COPY 20 #DISP
SUBI T 1 T
TJMP DISPLOOP
HALT
MARK CLEANUP
COPY 7 T
MARK CLNLOOP
SUBI T 1 T
TJMP CLNLOOP
KILL
There's no loop unrolling or anything and there's huge amounts of bills so this is slow.
Very slow. In fact, this takes almost a full minute to run all 100 tests at fast forward speed.
However, it does work, as you can see from the crowd of people flocking around the ATM.
The top percentiles are 1072, 14, and 10.
Let's start with improving activity. Since it always counts the worst test, the activity is 10 if you need to get EXAs to all 7 ATMs and only move the one to the host just before the ATMs. So the only activity step that can be removed is the one KILL instruction.
Well, that's easy enough if we don't care about making the code even slower.
code:
LINK 800
LINK 800
LINK 800
COPY 799 X
MARK CLONE
ADDI 1 X X
TEST X > 806
TJMP END
REPL CLONE
LINK X
COPY #CASH T
MARK DISPLOOP
COPY 20 #DISP
SUBI T 1 T
TJMP DISPLOOP
MARK END
That's quite nice, we also happen to be getting close to the top percentile in size. Only two more lines of code to get rid of.
The MARK END isn't actually required. We can TJMP from the CLONE loop to the DISPLOOP mark... it'll then try to COPY to #DISP which doesn't exist in that host and it'll crash. That's 15 LoC.
Also, the COPY from #CASH and the countdown in T can be combined into a single line by just testing #CASH directly each round.
3027/14/10
Let's go back to the initial solution and see if we can speed it up. With a max size of 50, we don't have much spare room for unrolling loops but we can do at least some.
code:
LINK 800
LINK 800
LINK 800
COPY 799 X
MARK CLONE
ADDI 1 X X
TEST X > 806
TJMP DISPLOOP
REPL CLONE
LINK X
MARK 33LP
@REP 33
COPY 20 #DISP
@END
TEST #CASH > 33
TJMP 33LP
MARK DISPLOOP
COPY 20 #DISP
TEST #CASH = 0
FJMP DISPLOOP
From that solution we can drop it to 1125/50/11, using this code:
code:
LINK 800
LINK 800
LINK 800
REPL CLEANUP
COPY 799 X
MARK CLONE
ADDI 1 X X
REPL CLONE
LINK X
MARK 28LP
@REP 28
COPY 20 #DISP
@END
TEST #CASH > 28
TJMP 28LP
MARK DISPLOOP
COPY 20 #DISP
DIVI X #CASH X
JUMP DISPLOOP
MARK CLEANUP
COPY 7 T
MARK CLNLOOP
SUBI T 1 T
TJMP CLNLOOP
KILL
And because increasing the size of the unroll is so important, I should focus on that, regardless of anything else.
For instance, replacing the cleanup code with the much uglier
code:
MARK CLEANUP
SUBI X 1 X
TEST X < -6
FJMP CLEANUP
KILL
Finally, I found one more minor improvement, but it's a bit of a weird one.
code:
LINK 800
LINK 800
LINK 800
REPL CLEANUP
COPY 799 X
MARK CLONE
ADDI 1 X X
REPL CLONE
LINK X
MARK 29LP
@REP 29
COPY 20 #DISP
@END
DIVI 28 #CASH T
FJMP 29LP
MARK DISPLOOP
COPY 20 #DISP
DIVI X #CASH X
JUMP DISPLOOP
MARK CLEANUP
SUBI X 1 X
TEST X < -6
FJMP CLEANUP
KILL
The DIVI 28 #CASH T line speeds up things slightly because it acts as a three-way test.
If #CASH is 29 or greater, the result will be 0, causing FJMP to jump back into the unroll and dispense 29 more bills.
If #CASH is smaller than 29 but greater than 0, the result is (rounded) 1, so it won't jump and continue to the DISPLOOP.
And if it's exactly zero, the EXA immediately crashes with a divide by zero error. This means that it doesn't even have to go into the DISPLOOP once if the amount of bills is a multiple of 29, which happens in some slow test, saving two cycles.
1120 is still almost 50 cycles away from the top percentile. I'm still missing a significant improvement somewhere. I was thinking about making a smaller unrolled loop after the big one - to more quickly deal with the remaining bills. But since that takes cycles from the large unrolled loop, that seems to make things slower overall. Perhaps there's a very specific combination that makes it faster but I haven't found it.
Alternatively I'd look into running the DISPLOOP code in parallel, but I'm not sure how to do that. There's no place for an extra EXA in the ATM hosts, so no other EXA can come in to kill the dispenser EXA. And communicating via M would be hard too - there's only one global M register for all EXAs, and waiting for a kill signal on M isn't any faster than an EXA handling that by itself.
So, let me know what I'm missing.
Well, that caused a bit of chaos.
But not as much as I hoped.
I wonder why.
And next time, more body hacking to slow down the Phage.
So you're going to be hacking your own heart.